# 全排列： https://leetcode-cn.com/problems/permutations/

class Solution:
    def permute(self, nums: list) -> list:
        ''' 
        全排列的话，那么就使用递归回溯求解: 看分析
                                                 数字数量            
                        []                  append(num) 1  --> pop  0   (for循环接着遍历，append(num)
               1        2        3          append(num) 2  --> pop  1   (for循环接着遍历，append(num)   
            2     3   1   3  1       2      append(num) 3  --> pop  2   (for循环接着遍历，append(num)
        3          2 3    1 2         1         return  3  (回溯)
        '''  
        rst = []
        def dfs(arr):
            if len(arr) == len(nums):
                rst.append(arr[:])
                return 
            
            for num in nums:
                if num in arr: continue
                arr.append(num)
                dfs(arr)
                # 列表是可变对象， 回溯时，要手动清除这次添加的元素
                arr.pop()

        dfs([])
        
        return rst


# 优化，if num in arr: continue
class Solution:
    def permute(self, nums: list) -> list:
        ''' 
            一个used 数组，来表示当前值是否已经遍历过了， 提高了时间复杂度，但是增加了空间复杂度。
        '''  
        rst = []
        used = [False] * len(nums)
        def dfs(arr):
            if len(arr) == len(nums):
                rst.append(arr[:])
                return 
            
            for i in range(len(nums)):
                if used[i] == True:
                    continue
                used[i] = True
                arr.append(nums[i])
                dfs(arr)
                # 列表是可变对象， 回溯时，要手动清除这次添加的元素
                arr.pop()
                used[i] = False

        dfs([])
        
        return rst


# 官方一种写法，看的不是很明白，可以去掉 used数组，但是不是按照字典序进行输出
class Solution:
    def permute(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        def backtrack(first = 0):
            # 所有数都填完了
            if first == n:  
                res.append(nums[:])
            for i in range(first, n):
                # 动态维护数组
                nums[first], nums[i] = nums[i], nums[first]
                # 继续递归填下一个数
                backtrack(first + 1)
                # 撤销操作
                nums[first], nums[i] = nums[i], nums[first]
        
        n = len(nums)
        res = []
        backtrack()
        return res


nums = [1,2,3]

s = Solution()
rst = s.permute(nums)
print(rst)